﻿using System;
using System.ServiceModel;
using System.ServiceModel.Channels;
using TIBCO.Rendezvous;

namespace Tibco.ServiceModel
{
    internal sealed class TibcoChannelFactory : ChannelFactoryBase<IOutputChannel>
    {
        private readonly BindingContext _context;

        private readonly Action<TimeSpan> _openMethod;

        private readonly TibcoTransportBindingElement _bindingElement;

        private NetTransport m_transport;
        private CMTransport m_cmTransport;

        public TibcoChannelFactory(BindingContext context)
        {
            this._context = context;
            this._openMethod = new Action<TimeSpan>(this.Open);
            this._bindingElement = context.Binding.Elements.Find<TibcoTransportBindingElement>();
            this.m_cmTransport = null;
        }

        protected override void OnAbort()
        {
            base.OnAbort();
            this.OnClose(this._context.Binding.CloseTimeout);
        }

        protected override IAsyncResult OnBeginOpen(TimeSpan timeout, AsyncCallback callback, object state)
        {
            return this._openMethod.BeginInvoke(timeout, callback, state);
        }

        protected override void OnClose(TimeSpan timeout)
        {
            this.m_cmTransport?.Destroy();
            this.m_transport?.Destroy();
            this.m_cmTransport = null;
            this.m_transport = null;            
        }

        protected override IOutputChannel OnCreateChannel(EndpointAddress address, Uri via)
        {
            return new TibcoOutputChannel(this._context, this.m_cmTransport, address);
        }

        protected override void OnEndOpen(IAsyncResult result)
        {
            this._openMethod.EndInvoke(result);
        }

        protected override void OnOpen(TimeSpan timeout)
        {
            TIBCO.Rendezvous.Environment.Open();

            this.m_transport = new NetTransport(_bindingElement.Service, _bindingElement.Network, _bindingElement.Deamon);
            this.m_cmTransport = new CMTransport(m_transport);
            //this._model = this._bindingElement.Open(timeout);
        }
    }
}